Caching a Template Fragment
What's Caching?
Storing a response into a file and using it for future
- Both on client and server
Symfony's solution
- Cache of an action (with or without the layout)
- Cache of a partial, a component, or a component slot
- Cache of a template fragment
You need to first enable caching in settings.yml
dev:
.settings:
cache: on
Frontend/modules/user/config/cache.yml
module: user action:list
list:
enabled
: on
with_layout
: false # Default value
lifetime
: 86400 # Default value
A complete one
list:
enabled
: on
show
:
enabled
: on
all
:
with_layout
: false # Default value
lifetime
: 86400 # Default value
- Even arguments can be handled by cache
- Actions called with a POST method or with GET parameters are not cached.
Partial, Component, Slots or Component Slots
Same
frontend/modules/user/config/cache.yml
_my_partial
:
enabled
: on
list:
enabled
: on
...
It can handle parameters as well.
<?php include_partial
('user/my_other_partial', array('foo' => 'bar')) ?>
Components
_day:
enabled: on
Template dependent or not?
_day:
contextual: true
enabled: on

part of a template
Example
<!-- Code executed each time -->
<?php echo link_to
('last accessed user', 'user/show?id='.$last_accessed_user_id) ?>
<!-- Cached code -->
<?php if (!cache
('users')): ?>
<?php foreach ($users as $user): ?>
<?php echo $user->getName() ?>
<?php endforeach; ?>
<?php cache_save
() ?>
<?php endif; ?>
Or...
<?php if (!cache('users', 43200)): ?>
$context->getViewCacheManager()->addCache('article', 'show', array(
'withLayout' => true,
'lifeTime' => 3600,
)); frontend/lib/conditionalCacheFilter.class.php
class conditionalCacheFilter
extends sfFilter
{
public function execute
($filterChain)
{
$context = $this->getContext();
if (!$context->getUser()->isAuthenticated())
{
foreach ($this->getParameter('pages') as $page)
{
$context->getViewCacheManager()->addCache($page['module'], $page['action'], array('lifeTime' => 86400));
}
}
// Execute next filter
$filterChain->execute();
}
}
filters.yml
...
security: ~
conditionalCache:
class: conditionalCacheFilter
param:
pages:
- { module: article, action: show }
cache: ~
...
Where to store?
factories.yml
view_cache:
class: sfFileCache
param:
automaticCleaningFactor: 0
cacheDir: %SF_TEMPLATE_CACHE_DIR%
You can also use apache-level caching for super-fast caching
The entire cache
// Erase the whole cache
> php symfony cache:clear
// Short syntax
> php symfony cc
// Erase only the cache of the frontend application
> php symfony cache:clear --app=frontend
// Erase only the HTML cache of the frontend application
> php symfony cache:clear --app=frontend --type=template
// Erase only the configuration cache of the frontend application
// The built-types are config, i18n, routing, and template.
> php symfony cache:clear --app=frontend --type=config
// Erase only the configuration cache of the frontend application and the prod environment
> php symfony cache:clear --app=frontend --type=config --env=prod
Selective Parts
public function executeUpdate($request)
{
// Update a user
$user_id = $request->getParameter('id');
$user = UserPeer::retrieveByPk($user_id);
$this->forward404Unless($user);
$user->setName($request->getParameter('name'));
...
$user->save();
// Clear the cache for actions related to this user
$cacheManager = $this->getContext()->getViewCacheManager();
$cacheManager->remove('user/list');
$cacheManager->remove('user/show?id='.$user_id);
...
}
Remove Partials
sf_cache_key is hard to memorize!
Instead, define your own cache key:
<? include_partial
('a1partial', array('i' => $i, 'sf_cache_key'=>$i)) ?>
...
<?php include_partial
('user/my_partial', array(
'user' => $user,
'sf_cache_key' => $user->getId()
) ?>
and remove it
$cacheManager->remove('@sf_cache_partial?module=user&action=_my_partial&sf_cache_key='.$user->getId());
Removing Template Fragments
<!-- Cached code -->
<?php if (!cache('users')): ?>
... // Whatever
<?php cache_save() ?>
<?php endif; ?>
// Is identified in the cache as
@sf_cache_partial?module=user&action=list&sf_cache_key=users
// Clear it with
$cacheManager->remove('@sf_cache_partial?module=user&action=list&sf_cache_key=users');
Cache dependencies
You need to be aware of caching problems.
Several Clearings at once
$cacheManager->remove('user/show?id=*'); // Remove for all user records
$cache->remove('user/show?sf_culture=*&id=12');
$cacheManager->remove('@sf_cache_partial?module=user&action=_my_partial&sf_cache_key=*'); // Remove for all keys
Specify host
$cacheManager->remove('user/show?id=*'); // Remove records for the current host and all users
$cacheManager->remove('user/show?id=*', 'life.askeet.com'); // Remove records for the host life.askeet.com and all users
$cacheManager->remove('user/show?id=*', '*'); // Remove records for every host and all users
Removing frontend cache from backend
$frontend_cache_dir = sfConfig
::get('sf_cache_dir').DIRECTORY_SEPARATOR
.'frontend'.DIRECTORY_SEPARATOR
.sfConfig
::get('sf_environment').DIRECTORY_SEPARATOR
.'template';
$cache = new sfFileCache
(array('cache_dir' => $frontend_cache_dir)); // Use the same settings as the ones defined in the frontend factories.yml
$cache->removePattern('user/show?id=12');
ETag
send as HTTP header, helps server to see if the content is modified, etc.
enbale it in symfony
all:
.settings:
etag: on
Last modified time
Server:
Last-Modified: Sat, 23 Nov 2006 13:27:31 GMT
Set it in symfony:
$this->getResponse()->setHttpHeader('Last-Modified', $this->getResponse()->getDate($timestamp));
Browser:
If-Modified-Since: Sat, 23 Nov 2006 13:27:31 GMT
Vary
Vary: Cookie
Symfony then caches depending on different parameters:
$this->getResponse()->addVaryHttpHeader('Cookie');
$this->getResponse()->addVaryHttpHeader('User-Agent');
$this->getResponse()->addVaryHttpHeader('Accept-Language');